package com.zis.platform.common.authentication;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.util.CollectionUtils;

import com.zis.platform.core.entity.DataAuthUserEntity;
import com.zis.platform.core.entity.GroupEntity;
import com.zis.platform.core.entity.ResEntity;
import com.zis.platform.core.entity.RoleEntity;
import com.zis.platform.core.entity.UserEntity;

/**
 * 
 * <b>说明：</b>针对shiro 的用户凭证做了扩展<br>
 * 新增了机构、用户数据权限、用户角色、用户菜单等内容<br>
 * 调用方法：UserToken userToken = (UserToken)SecurityUtils.getSubject().getPrincipal();
 * 
 * @ClassName: UserToken
 * @author zhaohaitao(2543)
 * @date 2015-7-10 上午10:06:11
 * 
 */
public class UserToken extends UsernamePasswordToken
{
    
    private static final long serialVersionUID = -7380585897168083685L;
    
    /**
     * 用户凭证 对应的用户信息实体
     */
    private UserEntity user;
    
    private GroupEntity userGroup;
    
    /**
     * 用户所拥有的系统权限
     */
    private List<String> sysIds = new ArrayList<String>();
    
    /**
     * 当前用户所拥有的数据权限
     */
    private Map<String, List<DataAuthUserEntity>> dataPermission;
    
    /**
     * 登录成功之后跳转到登录前访问的地址(暂时无用)
     */
    private String redirectUrl;
    
    /**
     * 当前用户所拥有的角色信息
     */
    private List<RoleEntity> roles;
    
    /**
     * 当前用户所拥有的系统 与 菜单资源
     */
    private Map<String, List<ResEntity>> sysMenus = new HashMap<String, List<ResEntity>>();
    
    public UserToken()
    {
        super();
    }
    
    public UserToken(String loginName, String password, boolean rememberMe, String host)
    {
        super(loginName, password, rememberMe, host);
    }
    
    /**
     * 根据系统ID获取当前登陆者可以合法访问的菜单资源树
     * 
     * @Title: getMenus
     * @param @param sysId
     * @return List<ResEntity> 返回类型
     * @throws
     */
    public List<ResEntity> getMenus(String sysId)
    {
        return sysMenus.get(sysId);
    }
    
    public void setMenus(List<ResEntity> menus)
    {
        reGrade(menus);
    }
    
    /**
     * 用户在会话失效之前停留的页面url
     * 
     * @Title: getRedirectUrl
     * @return String 返回类型
     * @throws
     */
    public String getRedirectUrl()
    {
        return redirectUrl;
    }
    
    public void setRedirectUrl(String redirectUrl)
    {
        this.redirectUrl = redirectUrl;
    }
    
    /**
     * 当前用户的所有角色信息
     * 
     * @Title: getRoles
     * @return List<RoleEntity> 返回类型
     * @throws
     */
    public List<RoleEntity> getRoles()
    {
        return roles;
    }
    
    public void setRolesAndUserGroup(GroupEntity userGroup, List<RoleEntity> roles)
    {
        this.roles = roles;
        List<ResEntity> resList = new ArrayList<ResEntity>();
        for (RoleEntity role : roles)
        {
            resList.addAll(role.getResList());
        }
        if (userGroup.getStatus())
        {
            resList.addAll(userGroup.getResList());
        }
        buildMenuTree(resList);
    }
    
    /**
     * 
     * @Title: buildMenuTree
     * @param @param resList 设定文件
     * @return void 返回类型
     * @throws
     */
    
    private void buildMenuTree(List<ResEntity> resList)
    {
        Map<String, ResEntity> buildMenusByResList = buildMenusByResList(resList);
        List<ResEntity> leafs = getLeafs(buildMenusByResList);
        if (CollectionUtils.isEmpty(leafs))
        {
            leafs.addAll(buildMenusByResList.values());
            Collections.sort(leafs);
            reGrade(leafs);
        }
        else
        {
            resetMenuTree(leafs, buildMenusByResList);
        }
    }
    
    /**
     * 
     * 根据用户所拥有的权限资源来组件菜单树
     * 
     * @Title: buildMenusByResList
     * @param @param resList
     * @param @return 设定文件
     * @return Map<String,ResEntity> 返回类型
     * @throws
     */
    public Map<String, ResEntity> buildMenusByResList(List<ResEntity> resList)
    {
        Map<String, ResEntity> menus = new HashMap<String, ResEntity>();
        if (!CollectionUtils.isEmpty(resList))
        {
            for (ResEntity res : resList)
            {
                if (res.getIsEnabled())
                {
                    if (StringUtils.isNotEmpty(res.getSysId()) && !sysIds.contains(res.getSysId()))
                    {
                        sysIds.add(res.getSysId());
                    }
                    List<ResEntity> childrenMenus = res.getChildrenMenus();
                    if (!CollectionUtils.isEmpty(childrenMenus))
                    {
                        menus.putAll(buildMenusByResList(childrenMenus));
                        menus.put(res.getResId(), res);
                    }
                    else
                    {
                        if (res.isMenu())
                        {
                            menus.put(res.getResId(), res);
                        }
                    }
                }
            }
        }
        return menus;
    }
    
    /**
     * 从菜单资源中获取所有的叶子节点
     * 
     * @param menusMap
     * @return
     */
    private List<ResEntity> getLeafs(Map<String, ResEntity> menusMap)
    {
        List<ResEntity> temp = new ArrayList<ResEntity>();
        Set<Entry<String, ResEntity>> entrySet = menusMap.entrySet();
        for (Entry<String, ResEntity> entry : entrySet)
        {
            ResEntity resEntity = entry.getValue();
            if (CollectionUtils.isEmpty(resEntity.getChildren()) && !StringUtils.isEmpty(resEntity.getParentId()))
            {
                temp.add(resEntity);
            }
        }
        return temp;
    }
    
    /**
     * 从叶子节点向上层节点进行遍历，组建用户权限范围内的菜单结构树
     * 
     * @param leafs
     * @param menusMap
     */
    private void resetMenuTree(List<ResEntity> leafs, Map<String, ResEntity> menusMap)
    {
        Map<String, ResEntity> temp = new HashMap<String, ResEntity>();
        Iterator<ResEntity> iterator = leafs.iterator();
        while (iterator.hasNext())
        {
            ResEntity res = iterator.next();
            if (res != null)
            {
                String parentId = res.getParentId();
                ResEntity parent = temp.get(parentId);
                if (parent == null)
                {
                    parent = menusMap.get(parentId);
                }
                if (parent != null)
                {
                    parent.addChildRes(res);
                    temp.put(parentId, parent);
                }
            }
        }
        if (temp.size() > 0)
        {
            leafs.clear();
            Collection<ResEntity> values = temp.values();
            leafs.addAll(values);
            resetMenuTree(leafs, menusMap);
        }
        else
        {
            // 对根节点菜单进行排序
            Collections.sort(leafs);
            if (!user.isSupperManager())
            {
                reGrade(leafs);
            }
        }
    }
    
    private void reGrade(Collection<ResEntity> leafs)
    {
        for (ResEntity res : leafs)
        {
            if (StringUtils.isNotEmpty(res.getSysId()))
            {
                List<ResEntity> list = sysMenus.get(res.getSysId());
                if (CollectionUtils.isEmpty(list))
                {
                    list = new ArrayList<ResEntity>();
                    list.add(res);
                    sysMenus.put(res.getSysId(), list);
                }
                else
                {
                    list.add(res);
                }
            }
        }
    }
    
    /**
     * 获取当前登录用户信息
     * 
     * @Title: getUser
     * @return UserEntity 返回类型
     * @throws
     */
    public UserEntity getUser()
    {
        return user;
    }
    
    public void setUser(UserEntity user)
    {
        this.user = user;
    }
    
    public Map<String, List<DataAuthUserEntity>> getDataPermission()
    {
        return dataPermission;
    }
    
    public void setDataPermission(Map<String, List<DataAuthUserEntity>> dataPermission)
    {
        this.dataPermission = dataPermission;
    }
    
    public List<String> getSysIds()
    {
        return sysIds;
    }
    
    public Map<String, List<ResEntity>> getSysMenus()
    {
        return sysMenus;
    }
    
    /**
     * @return userGroup
     */
    
    public GroupEntity getUserGroup()
    {
        return userGroup;
    }
    
}
